<template>
  <div class="space-y-4">
    <div>
      <label class="block text-sm font-medium text-gray-700 mb-2">
        {{ displayLabel }}
        <span v-if="required" class="text-red-500">*</span>
      </label>

      <!-- 上传区域 -->
      <div
        @click="triggerFileInput"
        @dragover.prevent
        @drop.prevent="handleDrop"
        class="relative border-2 border-dashed border-gray-300 rounded-lg p-6 text-center hover:border-gray-400 transition-colors cursor-pointer"
        :class="{ 'border-red-300': error }"
      >
        <input
          ref="fileInput"
          type="file"
          :accept="accept"
          :multiple="multiple"
          class="hidden"
          @change="handleFileSelect"
        />

        <!-- 上传图标和文字 -->
        <div v-if="!previewImages.length" class="space-y-2">
          <svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48">
            <path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
          </svg>
          <div class="text-sm text-gray-600">
            <span class="font-medium text-primary-600">{{ $t('upload.clickToUpload') }}</span>
            {{ $t('upload.dragFilesHere') }}
          </div>
          <p class="text-xs text-gray-500">
            {{ $t('upload.supportedFormats', { formats: acceptText, size: maxSizeMB }) }}
          </p>
        </div>

        <!-- 图片预览 -->
        <div v-else class="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
          <div
            v-for="(image, index) in previewImages"
            :key="index"
            class="relative group"
          >
            <img
              :src="image.url"
              :alt="`预览图 ${index + 1}`"
              class="w-full h-24 object-cover rounded-lg"
            />
            <button
              type="button"
              @click.stop="removeImage(index)"
              class="absolute -top-2 -right-2 bg-red-500 text-white rounded-full w-6 h-6 flex items-center justify-center text-xs hover:bg-red-600 transition-colors"
            >
              ×
            </button>
          </div>

          <!-- 添加更多图片按钮 -->
          <div
            v-if="multiple && previewImages.length < maxFiles"
            @click.stop="triggerFileInput"
            class="w-full h-24 border-2 border-dashed border-gray-300 rounded-lg flex items-center justify-center hover:border-gray-400 transition-colors cursor-pointer"
          >
            <svg class="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
            </svg>
          </div>
        </div>

        <!-- 上传进度 -->
        <div v-if="uploading" class="absolute inset-0 bg-white bg-opacity-75 flex items-center justify-center rounded-lg">
          <div class="text-center">
            <div class="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600 mx-auto"></div>
            <p class="mt-2 text-sm text-gray-600">上传中...</p>
          </div>
        </div>
      </div>

      <!-- 错误提示 -->
      <p v-if="error" class="mt-2 text-sm text-red-600">
        {{ error }}
      </p>

      <!-- 帮助文字 -->
      <p v-if="helpText" class="mt-2 text-sm text-gray-500">
        {{ helpText }}
      </p>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import { useI18n } from 'vue-i18n'
import {
  isValidImageFile,
  isValidFileSize,
  compressImage,
  getFilePreviewUrl,
  revokeFilePreviewUrl
} from '@/utils/helpers'
import { FILE_UPLOAD } from '@/constants'

interface PreviewImage {
  file: File
  url: string
}

interface Props {
  modelValue?: File | File[] | null
  label?: string
  accept?: string
  multiple?: boolean
  required?: boolean
  maxSizeMB?: number
  maxFiles?: number
  compress?: boolean
  helpText?: string
}

interface Emits {
  (e: 'update:modelValue', value: File | File[] | null): void
}

const props = withDefaults(defineProps<Props>(), {
  label: '',
  accept: 'image/*',
  multiple: false,
  required: false,
  maxSizeMB: FILE_UPLOAD.MAX_SIZE_MB,
  maxFiles: 5,
  compress: true,
  helpText: '',
})

const emit = defineEmits<Emits>()
const { t } = useI18n()

const fileInput = ref<HTMLInputElement>()
const previewImages = ref<PreviewImage[]>([])
const uploading = ref(false)
const error = ref('')

// 计算属性
const displayLabel = computed(() => {
  return props.label || t('upload.uploadImage')
})

const acceptText = computed(() => {
  if (props.accept === 'image/*') return 'JPG, PNG, GIF, WebP'
  return props.accept.replace(/image\//g, '').toUpperCase()
})

// 触发文件选择
const triggerFileInput = () => {
  fileInput.value?.click()
}

// 处理文件选择
const handleFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  const files = target.files
  if (files) {
    handleFiles(Array.from(files))
  }
}

// 处理拖拽上传
const handleDrop = (event: DragEvent) => {
  const files = event.dataTransfer?.files
  if (files) {
    handleFiles(Array.from(files))
  }
}

// 处理文件
const handleFiles = async (files: File[]) => {
  error.value = ''

  // 验证文件数量
  if (!props.multiple && files.length > 1) {
    error.value = t('upload.onlyOneFile')
    return
  }

  if (props.multiple && previewImages.value.length + files.length > props.maxFiles) {
    error.value = t('upload.maxFilesLimit', { max: props.maxFiles })
    return
  }

  uploading.value = true

  try {
    const validFiles: File[] = []

    for (const file of files) {
      // 验证文件类型
      if (!isValidImageFile(file)) {
        error.value = t('upload.invalidImageFormat', { name: file.name })
        continue
      }

      // 验证文件大小
      if (!isValidFileSize(file, props.maxSizeMB)) {
        error.value = t('upload.fileTooLarge', { name: file.name, size: props.maxSizeMB })
        continue
      }

      // 压缩图片
      let processedFile = file
      if (props.compress) {
        processedFile = await compressImage(file)
      }

      validFiles.push(processedFile)
    }

    if (validFiles.length === 0) {
      return
    }

    // 创建预览
    const newPreviews: PreviewImage[] = validFiles.map(file => ({
      file,
      url: getFilePreviewUrl(file),
    }))

    if (props.multiple) {
      previewImages.value.push(...newPreviews)
    } else {
      // 清理旧预览
      previewImages.value.forEach(preview => {
        revokeFilePreviewUrl(preview.url)
      })
      previewImages.value = newPreviews
    }

    // 更新值
    updateValue()

  } catch (err) {
    console.error('文件处理失败:', err)
    error.value = t('upload.processingFailed')
  } finally {
    uploading.value = false
  }
}

// 移除图片
const removeImage = (index: number) => {
  const preview = previewImages.value[index]
  revokeFilePreviewUrl(preview.url)
  previewImages.value.splice(index, 1)
  updateValue()
}

// 更新值
const updateValue = () => {
  const files = previewImages.value.map(preview => preview.file)

  if (props.multiple) {
    emit('update:modelValue', files.length > 0 ? files : null)
  } else {
    emit('update:modelValue', files.length > 0 ? files[0] : null)
  }
}

// 监听props变化
watch(
  () => props.modelValue,
  (newValue) => {
    if (!newValue) {
      // 清理预览
      previewImages.value.forEach(preview => {
        revokeFilePreviewUrl(preview.url)
      })
      previewImages.value = []
    }
  }
)
</script>
